# -*- coding: utf-8 -*-
# FileName:     zsimulators.py
# time:         23/1/7 007 上午 11:12
# Author:       Zhou Hang
# Description:  I don't want to write
import sys
from pathlib import Path

from PyQt5.QtGui import QTextCursor, QIcon
from PyQt5.QtWidgets import QMainWindow, QMessageBox

from common.zerror import MyCoreError
from ProcSims.src.core.lottery import LotteryCore
from ProcSims.src.core.mlfq import MLFQCore
from ProcSims.src.core.process_run import ProcessRunCore
from ProcSims.src.core.scheduler import SchedulerCore
from ProcSims.src.ui.zsimulators_ui import Ui_ZSimulators

simulator_list = ['process_run', 'scheduler', 'mlfq']
simulator_map_zh = {
    'process_run': '进程运行',
    'scheduler': '进程调度',
    'mlfq': '多级反馈队列'
}

switch_map = {
    'I/O时切换': 'SWITCH_ON_IO',
    '结束时切换': 'SWITCH_ON_END'
}

iodone_map = {
    '延迟执行': 'IO_RUN_LATER',
    '立即执行': 'IO_RUN_IMMEDIATE'
}

policy_map = {
    '短作业优先': 'SJF',
    '先入先出': 'FIFO',
    '轮询调度': 'RR'  # round-robin
}


class ZSimulators(QMainWindow, Ui_ZSimulators):
    def __init__(self):
        super(ZSimulators, self).__init__()
        self.core = None
        self.process_run_core = None
        self.tmp_file = '../output/tmp.txt'
        self.setupUi(self)

        self.init_common()
        self.init_process_run()
        self.init_scheduler()
        self.init_mlfq()
        self.init_lottery()

    # START COMMON
    def init_common(self):
        self.setWindowIcon(QIcon('../resources/main_icon.png'))
        self.exit_btn.triggered.connect(self.close)

    def run_core(self, Core, args=None):
        save_stdout = sys.stdout
        sys.stdout = open(self.tmp_file, "w", encoding='utf-8')
        try:
            if args is not None:
                self.core = Core(**args)
            else:
                self.core.show_args()  # 展示参数
        except MyCoreError as e:
            QMessageBox.warning(self, '警告', str(e))
            return
        finally:
            sys.stdout.close()
            sys.stdout = save_stdout

    def put_file_in_gui(self, to_display):
        result = Path(self.tmp_file)
        to_display.setText(result.read_text(encoding='utf-8'))
        to_display.moveCursor(QTextCursor.Start)

    @staticmethod
    def change_table(table, new_value, row_prompt):
        """
        这样封装感觉问题很大，过几天自己都不理解了
        主要功能是根据某个新值增删表格的行数
        :param table: 要修改的表格
        :param new_value: 新的目标行数
        :param row_prompt: 行标
        :return:
        """
        old_process_num = table.get_row_num()
        process_num = new_value
        if process_num > old_process_num:
            table.append_row(row_prompt)
        else:
            table.remove_last_row()
    # END COMMON

    # START process_run
    def init_process_run(self):
        self.processlist_table.update()
        self.switch_comb.addItems(switch_map.keys())
        self.iodone_comb.addItems(iodone_map.keys())
        self.process_run_btn.clicked.connect(self.process_run)
        self.process_num_sb.valueChanged.connect(self.change_processlist_table)

    def change_processlist_table(self):
        self.change_table(self.processlist_table, self.process_num_sb.value(), '进程')

    def process_run(self):
        args = {
            'seed': self.seed_sb.value(),
            'processlist': self.processlist_table.get_processlist(),
            'iolength': self.iolength_sb.value(),
            'switch': switch_map[self.switch_comb.currentText()],
            'iodone': iodone_map[self.iodone_comb.currentText()],
            'compute': self.compute_cb.isChecked(),
            'printstats': self.printstats_cb.isChecked()
        }
        self.run_core(ProcessRunCore, args)
        self.put_file_in_gui(self.process_run_edit)
    # END process_run

    # START scheduler
    def init_scheduler(self):
        self.policy_comb.addItems(policy_map.keys())

        self.jobs_sb.valueChanged.connect(self.change_jlist_table)
        self.scheduler_start_btn.clicked.connect(self.scheduler_start)

    def change_jlist_table(self):
        self.change_table(self.jlist_table, self.jobs_sb.value(), '作业')

    def scheduler_start(self):
        args = {
            'seed': self.seed_sb.value(),
            'jobs': self.jobs_sb.value(),
            'jlist': self.jlist_table.get_jlist(),
            'maxlen': self.maxlen_sb.value(),
            'policy': policy_map[self.policy_comb.currentText()],
            'quantum': self.quantum_sb.value(),
            'compute': self.compute_cb.isChecked()
        }
        self.run_core(SchedulerCore, args)
        self.put_file_in_gui(self.scheduler_edit)
    # END scheduler

    # START mlfq
    def init_mlfq(self):
        self.numJobs_sb.valueChanged.connect(self.change_mlfq_jlist_table)
        self.numQueues_sb.valueChanged.connect(self.change_mlfq_quantum_allotment_table)
        self.mlfq_start_btn.clicked.connect(self.mlfq_start)
        self.mlfq_start_btn2.clicked.connect(self.mlfq_start)

    def change_mlfq_jlist_table(self):
        self.change_table(self.jlist_table2, self.numJobs_sb.value(), '作业')

    def change_mlfq_quantum_allotment_table(self):
        numQueue = self.numQueues_sb.value()
        self.change_table(self.quantumList_table, numQueue, '队列')
        self.change_table(self.allotmentList_table, numQueue, '队列')

    def mlfq_start(self):
        args = {
            'seed': self.seed_sb.value(),
            'numQueues': self.numQueues_sb.value(),
            'quantum': self.quantum_sb2.value(),
            'allotment': self.allotment_sb.value(),
            'quantumList': self.quantumList_table.get_list(),
            'allotmentList': self.allotmentList_table.get_list(),
            'numJobs': self.numJobs_sb.value(),
            'maxlen': self.maxlen_sb2.value(),
            'maxio': self.maxio_sb.value(),
            'boost': self.boost_sb.value(),
            'iotime': self.iotime_sb.value(),
            'stay': self.stay_cb.isChecked(),
            'iobump': self.iobump_cb.isChecked(),
            'jlist': self.jlist_table2.get_jlist(),
            'compute': self.compute_cb.isChecked()
        }
        self.run_core(MLFQCore, args)
        self.put_file_in_gui(self.mlfq_edit)
        # 将参数显示在界面上
        self.run_core(None)
        self.put_file_in_gui(self.mlfq_args_edit)
        self.mlfq_args_edit.set_line_height(15)
    # END mlfq

    # START lottery
    def init_lottery(self):
        self.lottery_jobs_sb.valueChanged.connect(self.change_lottery_jlist_table)
        self.lottery_start_btn.clicked.connect(self.lottery_start)

    def change_lottery_jlist_table(self):
        self.change_table(self.lottery_jlist_table, self.lottery_jobs_sb.value(), '作业')

    def lottery_start(self):
        args = {
            'seed': self.seed_sb.value(),
            'jobs': self.lottery_jobs_sb.value(),
            'jlist': self.lottery_jlist_table.get_jlist() if self.lottery_jlist_cb.isChecked() else '',
            'maxlen': self.lottery_maxlen_sb.value(),
            'maxticket': self.maxticket_sb.value(),
            'quantum': self.lottery_quantum_sb.value(),
            'compute': self.compute_cb.isChecked()
        }
        self.run_core(LotteryCore, args)
        self.put_file_in_gui(self.lottery_edit)
    # END lottery


def main():
    pass


if __name__ == "__main__":
    main()
